home *** CD-ROM | disk | FTP | other *** search
- /*
- * $RCSfile: undoTransaction.c,v $
- * $Revision: 1.1.1.1 $
- * $Date: 1996/05/04 21:55:50 $
- */
- /**********************************************************************
- * EXODUS Database Toolkit Software
- * Copyright (c) 1991 Computer Sciences Department, University of
- * Wisconsin -- Madison
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
- * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
- * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
- * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * The EXODUS Project Group requests users of this software to return
- * any improvements or extensions that they make to:
- *
- * EXODUS Project Group
- * c/o David J. DeWitt and Michael J. Carey
- * Computer Sciences Department
- * University of Wisconsin -- Madison
- * Madison, WI 53706
- *
- * or exodus@cs.wisc.edu
- *
- * In addition, the EXODUS Project Group requests that users grant the
- * Computer Sciences Department rights to redistribute these changes.
- **********************************************************************/
-
- #include "sysdefs.h"
- #include "ess.h"
- #include "checking.h"
- #include "trace.h"
- #include "error.h"
- #include "list.h"
- #include "pool.h"
- #include "tid.h"
- #include "io.h"
- #include "lock.h"
- #include "object.h"
- #include "msgdefs.h"
- #include "thread.h"
- #include "semaphore.h"
- #include "latch.h"
- #include "link.h"
- #include "lsn.h"
- #include "bf.h"
- #include "log.h"
- #include "volume.h"
- #include "openlog.h"
- #include "trans.h"
- #include "logrecs.h"
- #include "undo.h"
- #include "threadstate.h"
- #include "bf_extfuncs.h"
- #include "util_funcs.h"
- #include "log_intfuncs.h"
- #include "log_extfuncs.h"
- #include "undo_extfuncs.h"
- #include "thread_globals.h"
- #include "io_globals.h"
- #include "log_globals.h"
- #include "trans_globals.h"
- #include "undo_globals.h"
-
-
- void
- undoTransaction (
-
- LSNOFFSET limitLSN,
- LSNOFFSET startLSN, /* NULL_LSN => use last transaction LSN */
- FLAGS flags
- )
- {
-
- register LOGRECORDHDR *recordHeader;
- register GROUPLINK *groupLink;
- register PAGE2SIZE page2size;
- register LSNOFFSET nextLSN;
- register LSNOFFSET offset;
- LSNOFFSET lastLSN;
- OPENLOG *openLog;
- PID pid;
- TRANSREC *transRec;
- LOGPAGEHDR *pageHeader;
- LOGPAGEHDR *endHeader;
- GROUPLINK *logRecordBuffer = NULL;
- #ifdef DEBUG
- LOGRECORDHDR *previousRecord;
- LOGPAGEHDR tempHeader;
- #endif
-
-
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("limitLSN:%d", limitLSN));
-
- PREVENT_FAST_IO();
-
- /*
- * put values in registers
- */
- openLog = &OpenLog;
- pid.volid = openLog->volid;
- page2size = openLog->page2size;
- transRec = (TRANSREC*) Active->transRec;
- PRINT_PROGRESS(("Undoing transaction:%d\n", transRec->tid));
-
- /*
- * If the requested starting log record is NULL and the
- * transaction is being undone in normal operations (ie. not
- * during recovery) then use the last log record generated by
- * the transaction as the starting point.
- */
- SM_ASSERT(LEVEL_3, ((flags & LOG_RECOVERY) == 1) == (TransInfo.logState == L_RECOVER));
- if ((startLSN == NULL_LSN) && !(flags & LOG_RECOVERY) ) {
- lastLSN = transRec->lastLSN;
- } else {
- lastLSN = startLSN;
- }
-
-
- #ifndef INIT_LRC_IS_LSN
- /*
- * set up structures for recording pages whose updates are missing
- */
- transRec->missingUpdateInfo = setupMissingUpdateInfo();
- if (transRec->missingUpdateInfo == NULL) {
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
- #endif INIT_LRC_IS_LSN
-
- /*
- * while there are records process the undo routines
- */
- recordHeader = NULL;
- while (lastLSN != limitLSN) {
-
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_2, ("lastLSN:%d", lastLSN));
-
- /*
- * get the latch on the log
- */
- if (waitLatch( &(openLog->logLatch), SHARE_LATCH )) {
-
- SM_ERROR(TYPE_FATAL, Active->errno);
- }
-
- /*
- * check to see if the log is in use
- *
- * Note that this logic should be changed to let more than
- * a single aborter be active. This would involve handling
- * buffer group overflow and coordinating undo buffer access.
- */
- if (waitSemaphore( &(openLog->readSemaphore) )) {
-
- SM_ERROR(TYPE_FATAL, Active->errno);
- }
-
- /*
- * calculate the page that will be read in disk blocks
- */
- pid.page = LSN_TO_BLOCK(lastLSN, openLog);
-
- /*
- * attempt to read the page
- */
- if ((groupLink = bf_ReadPage(openLog->readGroup, &pid,
- page2size, NOFLAGS)) == NULL) {
-
- SM_ERROR(TYPE_FATAL, Active->errno);
- }
-
- /*
- * setup pointers to the page head and tail
- */
- pageHeader = (LOGPAGEHDR *) groupLink->bufFrame;
- endHeader = (LOGPAGEHDR *) (((char *) pageHeader) + openLog->lastUsableByte);
-
- #ifdef DEBUG
- tempHeader = *pageHeader;
- #endif
- /*
- * check that the page numbers are correct
- */
- SM_ASSERT(LEVEL_1, pageHeader->pageNumber == LSN_TO_LOG_PAGE(lastLSN, openLog));
- SM_ASSERT(LEVEL_1, endHeader->pageNumber == LSN_TO_LOG_PAGE(lastLSN, openLog));
-
- /*
- * check the magic numbers
- */
- if (CHECK_LOGPAGE_MAGIC(pageHeader) || CHECK_LOGPAGE_MAGIC(endHeader)) {
-
- SM_ERROR(TYPE_FATAL, esmBADLOGPAGEHEADER);
- }
-
-
- /*
- * get the offset of the record
- */
- offset = LOG_PAGE_OFFSET(lastLSN, openLog);
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_2, ("offset:%d", offset));
- SM_ASSERT(LEVEL_3, offset <= pageHeader->lastRecord);
-
- /*
- * get a pointer to the record header
- */
- #ifdef DEBUG
- previousRecord = recordHeader;
- #endif DEBUG
- recordHeader = (LOGRECORDHDR *) (groupLink->bufFrame + offset);
-
- /*
- * check the record header magic, and make sure it belongs
- * to the transaction being undone
- */
- SM_ASSERT(LEVEL_1, !(CHECK_LOGRECORD_MAGIC(recordHeader)));
- SM_ASSERT(LEVEL_1, transRec->tid == recordHeader->tid);
-
- /*
- * print out the record information
- */
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_3, ("tid:%x", recordHeader->tid));
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_3, ("LSN:%d, LRC:%d",
- recordHeader->recordLSN.offset, recordHeader->actionLRC.count));
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_3, ("length:%d", recordHeader->length));
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_3, ("type:%d", recordHeader->type));
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_3, ("action:%d, actionPid:%d",
- recordHeader->action, recordHeader->actionPid.page));
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_3, ("imageCount:%d", recordHeader->imageCount));
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_3, ("prevLSN:%d", recordHeader->previousLSN));
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_3, ("undoLSN:%d", recordHeader->nextUndoLSN));
-
- #if TRACING IS_ENABLED
-
- {
- register int i;
-
- for (i = 0; i < recordHeader->imageCount; i++) {
-
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_3, ("offset:%d size:%d",
- recordHeader->imageOffset[i], recordHeader->imageSize[i]));
- }
- }
-
- #endif
-
- /*
- * get a pointer to the next log record to undo
- */
- if (recordHeader->type == LOG_REC_TYPE_COMPENSATION ||
- recordHeader->type == LOG_REC_TYPE_USER_COMPENSATION) {
-
- nextLSN = recordHeader->nextUndoLSN;
- TRPRINT(TR_LOG, TR_LEVEL_3, ("compensation undoNextLSN:%d", nextLSN));
-
- } else {
-
- nextLSN = recordHeader->previousLSN;
- TRPRINT(TR_LOG, TR_LEVEL_3, ("nextLSN:%d", nextLSN));
- }
-
- if ((recordHeader->type == LOG_REC_TYPE_COMMIT) ||
- (recordHeader->type == LOG_REC_TYPE_END)) {
- /*
- * We do not need to undo the the transaction since
- * it committed. Set things up so that we exit the
- * loop.
- */
- nextLSN = limitLSN;
-
- }
- else if ((recordHeader->type == LOG_REC_TYPE_SERVER_PREPARE) ||
- (recordHeader->type == LOG_REC_TYPE_COORD_PREPARE)) {
- /*
- * The fact that we are here means that we are definitely
- * undoing this transaction - so skip these reccords
- * and proceed to undo the rest
- */
- } else if ((offset + recordHeader->length) <= openLog->lastUsableByte) {
-
- /*
- * the record resides entirely on this page so
- * we can directly undo the action
- */
- undoAction(recordHeader);
-
- } else {
-
- SM_ASSERT(LEVEL_3, logRecordBuffer == NULL);
- logRecordBuffer = getLogRecordBuffer(recordHeader->length);
-
- /*
- * the log record must be copied into contiguous space in the
- * undo buffer provided for the log
- */
- if (combineRecord(openLog, recordHeader, (openLog->lastUsableByte - offset), TRUE, logRecordBuffer) != esmNOERROR) {
-
- /*
- * Check to make sure that this is recovery. In this case we
- * just ignore this record and proceed to the next
- */
- if (flags & LOG_RECOVERY) {
-
- SM_ERROR(TYPE_LOG, esmINTERNAL);
-
- } else {
-
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
-
- } else {
-
- /*
- * undo the action
- */
- undoAction((LOGRECORDHDR *) logRecordBuffer->bufFrame);
- }
-
- freeLogRecordBuffer(logRecordBuffer);
- logRecordBuffer = NULL;
- }
-
- /*
- * get a new last lsn
- */
- lastLSN = nextLSN;
-
- /*
- * release the page
- */
- bf_UnfixPage(groupLink, BF_DEFAULT, FALSE);
-
- /*
- * release semaphore and latch
- */
- signalSemaphore( &(openLog->readSemaphore) );
- signalLatch( &(openLog->logLatch) );
- }
-
- #ifndef INIT_LRC_IS_LSN
- /*
- * If information was maintained on missing updates,
- * free up the information
- */
- if (transRec->missingUpdateInfo) {
- freeMissingUpdateInfo();
- }
- #endif INIT_LRC_IS_LSN
-
- ALLOW_FAST_IO();
-
- SM_ASSERT(LEVEL_3, logRecordBuffer == NULL);
- }
-